﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using LF.Common;
using LF.Domain.Helper;
using LF.Domain.Services;
using Microsoft.SemanticKernel.Embeddings;
using Microsoft.SemanticKernel;
using OllamaSharp;

namespace LF.Domain.Services.Iml
{
#pragma warning disable SKEXP0001
    public class OllamaTextEmbeddingService : ITextEmbeddingService
#pragma warning restore SKEXP0001
    {
        readonly string _model = "nomic-embed-text:v1.5";
        private readonly IParamConfigManagerService _paramConfigManager;
        
        public OllamaTextEmbeddingService(IParamConfigManagerService paramConfigManager, string? model = null)
        {
            _paramConfigManager = paramConfigManager;
            if (!string.IsNullOrEmpty(model))
            {
                _model = model;
            }
        }
        
        public IReadOnlyDictionary<string, object?> Attributes => new Dictionary<string, object?> {
            { "model", _model},
            { "url", GetOllamaUrl()}
        };

        /// <summary>
        /// 获取单个文本的向量嵌入
        /// </summary>
        public async Task<float[]> GetEmbeddingAsync(string text)
        {
            using var ollama = new OllamaApiClient(GetOllamaUrl(), _model);
            var response = await ollama.EmbedAsync(text);
            var embed = new List<float>();
            foreach (var item in response.Embeddings)
            {
                embed.AddRange(item);
            }
            return embed.ToArray();
        }
        
        /// <summary>
        /// 批量获取文本的向量嵌入
        /// </summary>
        public async Task<List<float[]>> GetEmbeddingsAsync(List<string> texts)
        {
            var result = new List<float[]>();
            using var ollama = new OllamaApiClient(GetOllamaUrl(), _model);
            foreach (var text in texts)
            {
                var response = await ollama.EmbedAsync(text);
                var embed = new List<float>();
                foreach (var item in response.Embeddings)
                {
                    embed.AddRange(item);
                }
                result.Add(embed.ToArray());
            }
            return result;
        }
        
        /// <summary>
        /// 计算两个向量之间的余弦相似度
        /// </summary>
        public double CalculateSimilarity(float[] embedding1, float[] embedding2)
        {
            if (embedding1.Length != embedding2.Length)
                throw new ArgumentException("向量维度不匹配");

            double dotProduct = 0;
            double magnitude1 = 0;
            double magnitude2 = 0;

            for (int i = 0; i < embedding1.Length; i++)
            {
                dotProduct += embedding1[i] * embedding2[i];
                magnitude1 += embedding1[i] * embedding1[i];
                magnitude2 += embedding2[i] * embedding2[i];
            }

            magnitude1 = Math.Sqrt(magnitude1);
            magnitude2 = Math.Sqrt(magnitude2);

            if (magnitude1 == 0 || magnitude2 == 0)
                return 0;

            return dotProduct / (magnitude1 * magnitude2);
        }
        
        private string GetOllamaUrl()
        {
            try
            {
                var config = _paramConfigManager.GetByKey("ollama");
                return config?.Value ?? DomainConfig.OllamaConfig.BaseUrl;
            }
            catch
            {
                return DomainConfig.OllamaConfig.BaseUrl;
            }
        }
    }
}
